/*
 * @Description: hooks_demo
 * @Author: ZhouGe
 * @Date: 2021-05-12 09:31:21
 * @LastEditors: ZhouGe
 * @LastEditTime: 2021-05-12 15:47:20
 */
import React, { useState, useRef, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';

// 对于hooks的总结：
// 1.只能在函数式组件、或自定义hooks中使用。普通函数和类组件中不能使用
// 2.只能在函数的第一层调用hooks。不能放入if、for、或子函数下。hooks极度依赖定义的顺序
// 3.可安装eslint-plugin-react-hooks检测hooks规范。

function App() {
  // useState怎么玩 = 代替state
  let [name, setName] = useState('zhouge'); // 异步，组件更新，state值才会变成新值
  let [data, setData] = useState({ sex: '男', age: 10 }); // 一个组件可以创建多个useState，并且一个useState里可以有多个state
  // useRef怎么玩 = createRef的hook版，获取dom或获取组件渲染之前的数据，与useEffect结合使用
  let elp = useRef();
  // useEffect 副作用，用来操作网络请求、dom操作。
  let [show, setShow] = useState(true);

  let scrollY = useScrollY();

  return (
    <div>
      {/* <p ref={elp}>{name}</p>
      <p>{data.sex}</p>
      <p>{data.age}</p>
      <button
        onClick={() => {
          // setName('zhouge test');
          // setData({
          //   ...data,
          //   sex: data.sex == '男' ? '女' : '男',
          // });
          console.log(elp.current); //获取dom节点
        }}
      >
        显示全称
      </button> */}

      {/* {show ? <Course /> : ''}
      <button
        onClick={() => {
          setShow(!show);
        }}
      >
        {show ? '隐藏课程' : '显示课程'}
      </button> */}
      <div style={{ border: '1px solid #000', height: '1500px' }}>
        <p style={{ position: 'fixed', left: 0, top: 0 }}>
          当前滚动条位置是：{scrollY}
        </p>
      </div>
    </div>
  );
}

function Course() {
  const [course, setCourse] = useState('web 高级工程师');
  const [num, setNum] = useState(1);

  // useRef
  // 特点：数据更新时，不会自动更新。可用于对比更新前数据和更新后数据的变化
  // 当不传参的时候，他可以当做createRef的hook版使用，用于获取dom节点
  let prevCourse = useRef(course);
  let prevNum = useRef(num);

  // useEffect 相当于componeDidMount(组件挂载)、componentDidUpdate(组件更新)、componentWillUnmount(组件卸载)的集合体
  // 特点：
  // 1.依赖参数num，实际上可以传入数组，数据更新时，执行回调函数
  // 生命周期:
  // 组件挂载->执行副作用(回调函数)
  // -> 组件更新 -> 执行清理函数(返还函数) -> 执行副作用(回调函数)
  // -> 组件准备卸载 -> 执行清理函数(返还函数) -> 组件卸载
  useEffect(() => {
    console.log('组件挂载或者更新时触发, 回调函数');
    return () => {
      console.log('清理更新前的全局内容，或检测组件即将卸载，返回函数');
    };
  }, []);
  useEffect(() => {
    if (course != prevCourse.current || num != prevNum.current) {
      console.log(course, num);
      console.log(prevCourse.current, prevNum.current);
      // 如何当前值与上一次值不相等，代表组件有更新
      prevCourse.current = course;
      prevNum.current = num;
      console.log(prevCourse.current, prevNum.current);
    }
  }, [course, num]);
  return (
    <div>
      <div>
        选择课程:
        <select
          value={course}
          onChange={({ target }) => {
            setCourse(target.value);
          }}
        >
          <option value='web 全栈工程师'>web 全栈工程师</option>
          <option value='web 高级工程师'>web 高级工程师</option>
        </select>
      </div>
      <div>
        购买数量:
        <input
          type='number'
          value={num}
          min={1}
          onChange={({ target }) => {
            setNum(target.value);
          }}
        />
      </div>
    </div>
  );
}

// 自定义组件
function useScrollY() {
  let [scrollY, setScrollY] = useState(0);
  function scroll() {
    setScrollY(window.scrollY);
  }
  useEffect(() => {
    window.addEventListener('scroll', scroll);
    return () => {
      window.removeEventListener('scroll', scroll);
    };
  }, []);
  return scrollY;
}

export default App;
